package com.bjy.qa.agent.tools.juel;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.text.StringEscapeUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.zip.Deflater;

/**
 * BRTC 签名生成工具类
 */
public class BRTCSign {
    /**
     * 为了符合 url 编码规范，替换编码后的 base64 字符串中的 +,/,=
     * @param str 编码后的 base64 字符串中
     * @return
     */
    private String base64_url_encode(String str) {
        return str.replaceAll("\\+", "*").replaceAll("\\/", "-").replaceAll("\\=", "_"); // 将字符串中的+,/,=替换成*,-,_
    }

    /**
     * 使用 hmac sha256 生成 sig 字段内容,经过 base64 编码
     * @param appId appId
     * @param appSecret appSecret
     * @param userId 用户名,utf-8 编码
     * @param room 房间号
     * @param curr_time 当前生成 sig 的 unix 时间戳
     * @param expire 有效期,单位毫秒
     * @return
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws InvalidKeyException
     */
    private String hmacsha256(String appId, String appSecret, String userId, String room, long curr_time, long expire) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
        String content_to_be_signed = "TLS.identifier:" + userId + "\n"
                + "TLS.room:" + room + "\n"
                + "TLS.sdkappid:" + appId + "\n"
                + "TLS.time:" + curr_time + "\n"
                + "TLS.expire:" + expire + "\n";
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(appSecret.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(content_to_be_signed.getBytes("UTF-8"));
        return new String(Base64.getEncoder().encode(array));
    }

    /**
     * 压缩
     * @param bytes 待压缩的字节数组
     * @return
     */
    private byte[] compress(byte[] bytes) {
        byte[] output = new byte[1024];
        Deflater compresser = new Deflater();
        compresser.setInput(bytes);
        compresser.finish();
        int compressedDataLength = compresser.deflate(output);
        return Arrays.copyOf(output, compressedDataLength);
    }

    /**
     * 生成 BRTC 签名
     * @param appId appId
     * @param appSecret appSecret
     * @param userId 用户名,utf-8 编码
     * @param room 房间号
     * @param curr_time 当前生成 sig 的 unix 时间戳
     * @param expire 有效期,单位毫秒
     * @return
     */
    public String genSign(String appId, String appSecret, String userId, String room, long curr_time, long expire) {
        try {
            String hashhmacStr = hmacsha256(appId, appSecret, userId, room, curr_time, expire);
            LinkedHashMap<String, Object> signMap = new LinkedHashMap<String, Object>(); // 为了使输出键的顺序和输入的顺序保持一致，使用LinkedHashMap
            signMap.put("TLS.ver", "2.0");
            signMap.put("TLS.identifier", userId);
            signMap.put("TLS.room", room);
            signMap.put("TLS.sdkappid", appId);
            signMap.put("TLS.expire", expire);
            signMap.put("TLS.time", curr_time);
            signMap.put("TLS.sig", hashhmacStr.replaceAll("/", "\\\\/"));
            byte[] _compressed = compress((StringEscapeUtils.unescapeJava(JSONObject.toJSONString(signMap))).getBytes());
            byte[] _encodeCompress = Base64.getEncoder().encode(_compressed);
            String str = new String(_encodeCompress);
            return base64_url_encode(str);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
